CS 116: Introduction to Computer Science 2

CS 116 Tutorial 5 (Solutions): Accumulative Recursion and Generative Recursion

Reminders:

  • Assignment 05 is due on Wed, Feb 26th at 10am

  1. Write an accumulatively recursive function record_digit(n) that returns a list of integers of length 10, with each index from 0 to 9 represents a corresponding digit's total appearances in the integer n.You cannot use L.count().

    For example,
    record_digit(19990514)=>[1,2,0,0,1,1,0,0,0,3]

    Solution:

    import check
    
    def record_digit_acc(s,i,acc):
       '''
       returns a list of natural numbers indicating the appreances of each digit in s,
       by going through every index i of s and mutating a 10-element list acc.
       
       Effects: acc is mutated.
       
       record_digit_acc: Str Nat (listof Nat) -> (listof Nat)
       Requires: 
          * i == 0
          * len(acc) == 10
          * acc.count(0)==10
       '''
       if i == len(s):
          return acc
       else:
          acc[int(s[i])]+=1
          return record_digit_acc(s,i+1,acc)
    	   
    def record_digit(n):
       ''' 
       returns a list of natural numbers indicating the appreances of each digit in 
       n.
       
       record_digit: Nat -> (listof Nat)
       
       Examples:
       record_digit(0) => [1,0,0,0,0,0,0,0,0,0]
       record_digit(1234567890) => [1,1,1,1,1,1,1,1,1,1]
       '''
       acc = [0]*10
       return record_digit_acc(str(n),0,acc)
    
    # Tests
    check.expect("record_digit1",record_digit(0),[1,0,0,0,0,0,0,0,0,0])
    check.expect("record_digit2",record_digit(1234567890),[1,1,1,1,1,1,1,1,1,1])
    check.expect("record_digit3",record_digit(19990514),[1,2,0,0,1,1,0,0,0,3])
    check.expect("record_digit4",record_digit(333),[0,0,0,3,0,0,0,0,0,0])
    
    

  2. Write an accumulatively recursive function count_max that consumes a nonempty list of numbers alon and returns the number of times the largest number in alon appears.

    For example,
    count_max([1, 3, 5, 4, 2, 3, 3, 3, 5]) => 2
    since the largest element of the list, 5 appears twice. Your function should pass through the list only once.

    import check
    
    
    def count_max_acc(lst, max_so_far, occurrences):
    
       ''' count_max_acc(lst, max_so_far, occurrences) returns occurences + the number 
           of times max_so_far appears in lst if max_so_far >= maximum value in lst; 
           or returns the number of time the maximum values in lst occurs if 
           max_so_far < maximum value in lst.
           
           count_max_acc: (listof Int) Int Nat -> Nat '''  
            
       if lst == []:
          return occurrences
       elif lst[0] > max_so_far:
          return count_max_acc(lst[1:], lst[0], 1)
       elif lst[0] == max_so_far:
          return count_max_acc(lst[1:], max_so_far, (occurrences+1))
       else:
          return count_max_acc(lst[1:], max_so_far, occurrences)		
    
    
    
    
    def count_max(alon):
    
       ''' count_max(alon) returns the number of occurrences of 
           the largest number in alon.
           
           count_max: (listof Int) -> Nat
           
           requires: alon is non empty
           
           Examples:
           count_max([-4]) => 1
           count-max([1, 3, 5, 4, 2, 3, 3, 3, 5]) => 2 '''  
           
       return count_max_acc(alon[1:], alon[0], 1)
    
    # Tests for count_max
    check.expect("Q2T1", count_max([-4]), 1)
    check.expect("Q2T2", count_max([4, 4, -1]), 2)
    check.expect("Q2T3", count_max([-7, -8, 12]), 1)
    check.expect("Q2T4", count_max([1, 3, 5, 4, 2, 3, 3, 3, 5]), 2)
    
    

  3. Write a function smaller consumes a non-empty string called s containing only numeric characters by repeatedly removing the larger of the first and last characters in s . if the first and the last number are the same, remove the last one.

    For example, starting from "5284, compare "5" and "4", and recurse on "284", which will compare "2" and "4", and recurse on "28". Comparing "2" and "8", leads to recursing on "2", which is the answer (since it is a string of length 1).

    Note: min is not allowed to use in this question.


    For example:

    smaller("4325") => "2"
    smaller("1") => "1"
    smaller("2325") => "2"

    Solution:

    import check
    
    
    def smaller(s):
    
       ''' smaller(s) returns the single digit obtained by repeatedly removing the
           larger of the first or last digits in the list, or the last one if 
           they are the same. 
           
           smaller: Str -> Str
           
           requires: len(s) > 0
    	      s contains only digits
    	      
           Examples:
           smaller("1") => "1"
           smaller("5284") => "2" '''   
       if len(s) == 1:
          return s
       else:
          first = int(s[0])
          last = int(s[-1])
          if first <= last:
    	 return smaller(s[:-1])
          else:
    	 return smaller(s[1:])
    
    # Tests
    check.expect("T1", smaller("1"), "1")
    check.expect("T2", smaller("5284"), "2")
    check.expect("T3", smaller("123456"), "1")
    check.expect("T4", smaller("99999"), "9")
    check.expect("T5", smaller("12121"), "1")
    check.expect("T6", smaller("9321123"), "1")
    
    

  4. Given a list L of positive integers, what is the skip-value of the list?

    • If L is empty,the skip value is 0.
    • If L is not empty:
      • Add one to the current skip value
      • Move ahead in the list by n (where n is the first element in the list) and repeat the process

    Write a function skip_value to calculate the skip value of the list L.

    For example:
    skip_value([]) => 0
    skip_value([1,1,1]) => 3
    skip_value([2,100,1]) => 2
    

    Solution:

    import check
    
    
    def skip_value(L):
    
       ''' skip_value(L) returns the skip value of a list of positive integers L.
       
             skip_value: (listof Nat) -> Nat
             
             requires: elements in L are positive integers
             
             Examples:
             skip_value([]) => 0
             skip_value([1,1,1]) => 3 '''
       
       if L == []:
          return 0
       else:
          next_step = L[0]
          if next_step > len(L):
             return 1
          else:
             return 1+skip_value(L[next_step:])
    
    # Tests
    check.expect("Skip-T1", skip_value([]), 0)
    check.expect("Skip-T2", skip_value([1,1,1]), 3)
    check.expect("Skip-T3", skip_value([2,100,1]), 2)
    

  5. Develop an accumulatively recursive function list_to_num that consumes a nonempty list, digits, of integers between 0 and 9, and returns the number corresponding to digits.

    For example,
    list_to_num([9, 0, 8]) => 908
    list_to_num([8, 6]) => 86.
    list_to_num([0, 6, 0]) => 60.

    Solution:

    import check
    
    
    def list_to_num_acc(dig, num_so_far):
    
       ''' list_to_num_acc(dig, num_so_far) adds the digits in dig 
           to the end of num_so_far, eventually returns natural number,
           which is the newest num_so_far 
           
           list_to_num_acc: (listof Nat) Nat -> Nat 
           '''   
       if dig == []:
          return num_so_far
       else:
          num_so_far = (10 * num_so_far) + dig[0]
          return list_to_num_acc(dig[1:], num_so_far) 
    
    
    
    def list_to_num(digits):
    
       ''' list_to_num(digits) builds a number from its list of digits
       
           list_to_num: (listof Nat) -> Nat
           
           requires: digits is nonempty
    	         number in digits is between 0 to 9
    	         
           Examples:
           list_to_num([9, 0, 8]) => 908
           list_to_num([8, 6]) => 86 '''   
           
       return list_to_num_acc(digits, 0)
    
    # Tests
    check.expect("Q1T1", list_to_num ([9, 0, 8]), 908)
    check.expect("Q1T2", list_to_num([0]), 0)
    check.expect("Q1T3", list_to_num([8, 6]), 86)